/*
 * ml20gui - The MSN Webcam Recorder
 * This source code is under the GNU Public License (GPL).
 * Written by Ramiro Polla
 * Initial release: june 3rd, 2005
 *
 * this program records MSN Webcam Video
 */

#ifndef ML20GUI_H
#define ML20GUI_H

#include <pcap.h>

#include <windows.h>

#define _WIN32_IE 0x400
#include <commctrl.h>

#include <stdio.h>
#include <sys/stat.h>

#include "resource.h"

#include "sysdep.h"
#include <vfw.h>

#include <shlwapi.h>
#include <shlobj.h>

#include "ml20dll.h"
#include "lang.h"

typedef u_long tcp_seq;

/**************************** Constants ***********************************/

#define SNAPLEN     65536 /* largest possible MTU we'll see */

//proc addresses
#define proc_700777 0x00739cf0
#define proc_700816 0x00742e90
#define proc_750299 0x00770290

/**************************** Structures **********************************/

// winpcap devices
typedef struct device {
    struct device *next;
    pcap_t *pd;
    pcap_if_t *d;
    int hdrsz;
    struct bpf_program fcode;
    int flags;
    char *name;
    char *description;
    int bytes;
} device_t;

struct tcphdr {
    u_short th_sport;   /* source port */
    u_short th_dport;   /* destination port */
    tcp_seq th_seq;     /* sequence number */
    tcp_seq th_ack;     /* acknowledgement number */
    uint8_t th_off;
    uint8_t th_flags;
    u_short th_win;     /* window */
    u_short th_sum;     /* checksum */
    u_short th_urp;     /* urgent pointer */
};

/* IPv4 header */
struct ip {
    uint8_t     ver_ihl;     // Version (4 bits) + Internet header length (4 bits)
    uint8_t     ip_tos;      // Type of service
    uint16_t    ip_len;      // Total length
    uint16_t    ip_id;       // Identification
    uint16_t    ip_off;      // Flags (3 bits) + Fragment offset (13 bits)
    uint8_t     ip_ttl;      // Time to live
    uint8_t     ip_p;        // Protocol
    uint16_t    ip_sum;      // Header checksum
    struct in_addr  ip_src; // Source address
    struct in_addr  ip_dst; // Destination address
};

typedef struct {
  uint32_t src;     /* Source IP address */
  uint32_t dst;     /* Destination IP address */
  uint16_t sport;   /* Source port number */
  uint16_t dport;   /* Destination port number */
} flow_t;

// Since the pattern for Video Conversations is not so easy to spot,
// there might be many false positives. So wait for x packets, and
// check if at least y% is valid.
// Educated guess:
// x = 20
// y = 80%
typedef struct possible_vc_s {
    char *data;
    int length;
    uint8_t ok;
    uint8_t notok;
} possible_vc_t, *possible_vc_p;

typedef struct stream_struct {
    struct stream_struct *next;
    //struct stream_struct *previous;
    flow_t *flow;
    tcp_seq isn;
    int flags;
    int offset;
    time_t start_time;
    unsigned int size;
    FILE *fp;
    char *fname;
    possible_vc_t pvc;
    DWORD last_time;    // so that they can be cleaned on timeout.
} stream_t;

#define AVIFILEOPEN             1
#define AVISAVEOPTIONS          2
#define AVIFILECREATESTREAM     3
#define AVIMAKECOMPRESSEDSTREAM 4
#define AVISTREAMSETFORMAT      5
#define CLEAN_ALL               6

typedef struct avifile_s {
    decoder_t *decoder;         // selection to be exported

    PAVIFILE pfile;
    PAVISTREAM ps, psCompressed;
    AVISTREAMINFOA si;
    AVICOMPRESSOPTIONS opts[1];
    LPAVICOMPRESSOPTIONS popts[1];

    char fname[MAX_PATH];
    int exporting;

    int fps;
    int exp_i;
    int imp_i;

    DWORD firsttick;
} avifile_t;

typedef struct hplay_s {
    struct hplay_s *next;       // next hplay_t
    struct hplay_s *previous;   // previous hplay_t
    HWND hwnd;                  // hwnd
    HWND phwnd;                 // play window's hwnd
    HICON Sicon;
    HICON Licon;

    vstream_t *vstream;         // virtual stream
    decoder_t *decoder;         // decoder
    int outf;                   // current out frame (for time)

    DWORD firsttick;            // first tick on current play

    int playing;                // is playing?
    int ID_TIMER;               // timer id
    int play_static;            // time to maintain text in static

    int ret;                    // return value used to see if you can close
    stream_t *stif;             // stream (if any)

    uint8_t *sdata;
    vframe_t *sframe;
    BITMAPINFOHEADER sbmi;
} hplay_t;

typedef struct hexport_s {
    struct hexport_s *next;     // next hexport_t
    struct hexport_s *previous; // previous hexport_t
    HWND hwnd;                  // hwnd
    hplay_t *thplay;            // parent
    vstream_t *vstream;         // common pointer to hplay
    decoder_t *decoder;         // copy from hplay (to maintain in and out)
    avifile_t *avifile;         // avi file struct to use
    unsigned int priority;
    int ID_TIMER;
    DWORD dwThreadId;
    HANDLE handle;
} hexport_t;

typedef struct ipp_s {
    unsigned int ip;
    struct ipp_s *next;
} ipp_t;

typedef struct invite_s {
    struct invite_s *next;      // next invite_t
    struct invite_s *previous;  // previous invite_t

    char *name;                 // user name
    flow_t flow;                // flow information
    ipp_t *ipp;                 // ipp
    unsigned char port;         // not yet used
} invite_t;

#define CODECS_LOCAL    (1 << 0)
#define CODECS_REMOTE   (1 << 1)

typedef struct msns_s {
    struct msns_s *next;
    msn_t msnt;
} msns_t;

typedef struct codecs_s {
    int flags;
    msns_t *first;
    int default_c;
} codecs_t;

/***************************** Macros *************************************/

#define IS_SET(vector, flag)    ((vector) & (flag))
#define SET_BIT(vector, flag)   ((vector) |= (flag))
#define UNSET_BIT(vector, flag) ((vector) &= (-1) - (flag))

// a stream_t structure can be:
#define FLOW_NEW            (1 << 0)

#define FLOW_LIVE           (1 << 1)
#define FLOW_DEAD           (1 << 2)

#define FLOW_ML20           (1 << 3)
#define FLOW_UDP            (1 << 4)
#define FLOW_POSSIBLE_VC    (1 << 5)
#define FLOW_VC             (1 << 6)

#define FLOW_USED           (1 << 7)
#define FLOW_RESTARTED      (1 << 8)
#define FLOW_STOPPED        (1 << 9)
#define FLOW_IMAGE          (1 << 10)

#define DO_CAP              (1 << 0)
#define NO_CAP              (1 << 1)
#define OFFLINE_CAP         (1 << 3)
#define PROMISCUOUS_CAP     (1 << 4)

#define READ_DATA           (1 << 0)
#define READ_SEEK_IN        (1 << 1)
#define READ_SEEK_OUT       (1 << 2)
#define READ_SEEK_FIRST     (1 << 3)
#define READ_RET_IN         (1 << 4)

#define FOURCC_ML20 mmioFOURCC( 'M', 'L', '2', '0' )
#define FOURCC_LM20 mmioFOURCC( 'L', 'M', '2', '0' )

/************************* Function prototypes ****************************/

/* ml20gui.c */
msn_t *get_default_codec( int flags );
void update_main_menu( HWND hwnd );

/* export.c */
int export_video_start( hexport_t *thexport );
int export_video_frame( hexport_t *thexport );
void export_video_end( hexport_t *hexport );

/* files.c */
FILE *open_file( stream_t *stream );
void close_file(stream_t *stream);
void get_fullname( char *inname, char *outname );
void make_fullname( stream_t *stream, char *fname );
char *build_streamname( stream_t *stream );
const char *flags_extension( int flags );
int extension_flags( const char *extension );

/* flows.c */
stream_t *identify_flow( uint32_t src, uint32_t dst, uint16_t sport, uint16_t dport, const uint8_t *data, uint32_t length );
void init_streams();
stream_t *create_stream(flow_t *flow);
stream_t *find_stream(flow_t *flow);
void close_flow_files( );
invite_t *create_invite( flow_t *flow );
invite_t *find_invite(flow_t *flow);
invite_t *find_invite_ip(flow_t *flow, int type);
#define TYPE_SRC    (1 << 0)
#define TYPE_DST    (1 << 1)

/* ip.c */
stream_t *process_ip(const uint8_t *data, uint32_t length);

/* record.c */
void add_dead_item( char *fname );
void add_live_item( stream_t *stream );
int is_vc( uint8_t *data, uint32_t length, int checkcode );
void dump_vc_data( FILE *fp, uint8_t *data, uint32_t length );
int look_for_stuff( uint8_t *data, uint32_t length, flow_t *flow );
int add_image( char *fname );
int read_lastfile( char *buf, int *buflen );
void write_lastfile( char *filename );

/* dialogs.c */
void *GetDlgListItem( HWND hwnd, int id, int index );
void SetDlgListImage( HWND hwnd, int id, int index, int image );
char *SaveFileDlg( HWND hwnd, char *filter, char *ext, char *fname );
char *OpenFileDlg( HWND hwnd, char *filter, char *ext );
int GetDlgListSelection( HWND hwnd, int id );
void add_lvcolumn( HWND hwnd, int ID, int subitem, char *text, int cx, int fmt );
int GetDlgButtonCheck( HWND hwnd, int id );
void lvcolumn_text( HWND hwnd, int ID, int subitem, char *text );

/* codecsdlg.c */
LRESULT CALLBACK CodecsProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
codecs_t *new_codecs( void );

/* aboutdlg.c */
LRESULT CALLBACK AboutProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
char *getbrowser( );

/* crashdlg.c */
LRESULT CALLBACK CrashProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

/* avidlg.c */
LRESULT CALLBACK AviProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
char *clean_export( hexport_t *hexport, int exp_ret );

/* interfaces.c */
LRESULT CALLBACK IntProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
int find_hdrsize( pcap_t *pd );

/* playdlg.c */
LRESULT CALLBACK PlayProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK PlayWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void resizebits( uint8_t *output, int ow, int oh, uint8_t *input, int iw, int ih, int ix, int irw );

/* getversion.c */
void *gvtaddress( );
int gvtsize( );
char *get_pid_filename( int pid );

/* avifile.c */
avifile_t *new_avifile( void );
void kill_avifile( avifile_t *avifile );

/* reg.c */
void reg_write_dword ( char *name, uint32_t  dword );
int  reg_read_dword  ( char *name, uint32_t *dword );
void reg_write_string( char *name, uint8_t  *str, int  len );
int  reg_read_string ( char *name, uint8_t  *str, int *len );

//STRINGS
#endif
